/*
 * Copyright (c) 2011.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.skavookie

import expressions.LiteralExpr
import math.Numeric

/**
 * Created by IntelliJ IDEA.
 * User: joshua
 * Date: 5/24/11
 * Time: 11:45 AM
 * To change this template use File | Settings | File Templates.
 */

/** This package object contains the definition of `KeyType` and several impicits. */
package object expressions {
	type KeyType = Any

	val byteIsIntegral = Numeric.ByteIsIntegral

	implicit def lit2tlit[T](lit: T)(implicit m: Manifest[T]): TLiteral[T] = LiteralExpr(lit)(m)
	implicit def tlit2lit[T](tlit: TLiteral[T]): T = tlit.literal
	implicit def tlit2litnum[T: Numeric](tlit: TLiteral[T]) =
		LiteralNumeric(tlit.literal)(implicitly[Numeric[T]], tlit.manifest)

	object Literal {
		def apply(lit: Byte): TLiteral[Byte] = LiteralIntegral(lit)
		def apply(lit: Int): TLiteral[Int] = LiteralIntegral(lit)
		def apply(lit: Long): TLiteral[Long] = LiteralIntegral(lit)
		def apply(lit: Double): TLiteral[Double] = LiteralFractional(lit)
		def apply(lit: Float): TLiteral[Float] = LiteralFractional(lit)
		def apply[T <: AnyRef](lit: T)(implicit m: Manifest[T]): TLiteral[T] = LiteralExpr(lit)

		def unapply[T](lit: TLiteral[T]) =
			Some((lit.getLiteral, lit.getManifest, lit match {
				case l@LiteralIntegral(_) => l.getIntegral
				case l@LiteralFractional(_) => l.getFractional
				case other => null
			}))
	}

/*
	trait NumericExprIsNumeric[T, NumericExpr[T]] extends Numeric[NumericExpr[T]] {
    def plus(x: NumericExpr[T], y: NumericExpr[T]): NumericExpr[T] = PlusExpr(x, y)
    def minus(x: NumericExpr[T], y: NumericExpr[T]): NumericExpr[T] = MinusExpr(x, y)
    def times(x: NumericExpr[T], y: NumericExpr[T]): NumericExpr[T] = TimesExpr(x, y)
    def negate(x: NumericExpr[T]): NumericExpr[T] = NegateExpr(x)
    def fromInt(x: Int): NumericExpr[T] = LiteralNumeric[T](x.asInstanceOf[T])

		protected def tryToEval[OT <% T](expr: NumericExpr[T], vis: NumericExprVisitor = Optimizer): OT =
			vis.visit(expr) match {
				case e: TLiteral[_] => e.getLiteral.asInstanceOf[OT]
				case other => throw new NoSuchElementException("Was expecting a lit of type %s, but got %s.".format(om, other))
			}
    def toInt(x: NumericExpr[T]): Int = x.getLiteral.toInt
    def toLong(x: NumericExpr[T]): Long = x.getLiteral.toLong
    def toFloat(x: NumericExpr[T]): Float = x.getLiteral.toFloat
    def toDouble(x: NumericExpr[T]): Double = x.getLiteral.toDouble
	}
*/
}